package com.xwy.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * <p>Title:JWT工具类</p>
 * <p>Description:使用HS512对称加密算法生成JWT</p>
 *
 * @author hjx
 * @date 2020/6/4 - 8:35
 */
@ConfigurationProperties(prefix = "auth0")
@Component
public class JwtAuthTokenUtil {
    private String secret;
    private int expiration;//过期时间
    private String header;

    public JwtAuthTokenUtil() {
        this.secret = "ZGElMjYlNUVhc2Rqbmo=";
        this.expiration = 2;
        this.header = "JWTHeaderName";
    }

    /*
        private String iss;//发布者
        private String sub;//主题
        private Date iat;//生成时间
        private String aud;//接受者
        private String nbf;//生效时间
    */
    public String createToken(String username) {
        try {
            //设置加密方式
            Algorithm algorithm = Algorithm.HMAC512(secret);
            Date date = new Date();
            return JWT.create()
                    .withIssuer("hjx")
                    .withSubject(username)
                    .withIssuedAt(date)
                    .withExpiresAt(DateUtils.addHours(date, expiration)) //时间单位为小时
//                    .withAudience(username)
                    .sign(algorithm);
        } catch (JWTCreationException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 解码成功则会从token中获取用户名信息
     *
     * @param token
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getSubject();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 验证JWT令牌 验证的过程中会自动去验证时间
     *
     * @param token 令牌
     * @return 返回验证结果
     */
    public boolean verifierToken(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC512(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withIssuer("hjx")
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (JWTVerificationException e) {
            //无效的 签名/声明
            System.out.println("无效签名");
            e.printStackTrace();
            return false;
        }
    }

    public boolean isTokenExpired(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            Date expiration = jwt.getExpiresAt();
            return expiration.before(new Date());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 刷新token 信息使用旧token的 刷新时间
     *
     * @param token 旧token
     * @return 新token
     */
    public String refreshToken(String token) {
        DecodedJWT oldJwt = JWT.decode(token);
        Algorithm algorithm = Algorithm.HMAC512(secret);
        Date date = new Date();
        return JWT.create()
                .withIssuer(oldJwt.getIssuer())
                .withSubject(oldJwt.getSubject())
                .withIssuedAt(date)
                .withExpiresAt(DateUtils.addHours(date, expiration))
                .sign(algorithm);
    }

    public String getSecret() {
        return secret;
    }

    public JwtAuthTokenUtil setSecret(String secret) {
        this.secret = secret;
        return this;
    }

    public int getExpiration() {
        return expiration;
    }

    public JwtAuthTokenUtil setExpiration(int expiration) {
        this.expiration = expiration;
        return this;
    }

    public String getHeader() {
        return header;
    }

    public JwtAuthTokenUtil setHeader(String header) {
        this.header = header;
        return this;
    }

}
